"""
点管理模块 - 完整修复版本
负责记录、存储和管理屏幕坐标点
"""

import os
import json
import logging
from typing import List, Tuple, Optional, Dict, Any
from dataclasses import dataclass, asdict
import pyautogui

logger = logging.getLogger(__name__)


@dataclass
class Point:
    """点数据类 - 完整修复版本"""
    x: int
    y: int
    text: str = ""
    click_type: str = "单击"
    delay_after: float = 0.5
    is_image: bool = False
    description: str = ""  # 新增：点描述
    enabled: bool = True   # 新增：是否启用

    def to_tuple(self) -> Tuple[int, int, str, str, float, bool, str, bool]:
        """转换为元组格式（扩展版本）"""
        return (self.x, self.y, self.text, self.click_type,
                self.delay_after, self.is_image, self.description, self.enabled)

    def to_dict(self) -> Dict[str, Any]:
        """转换为字典格式"""
        return asdict(self)

    @classmethod
    def from_tuple(cls, point_tuple: Tuple) -> 'Point':
        """从元组创建Point对象 - 修复版本"""
        try:
            # 处理不同版本的元组格式
            if len(point_tuple) == 8:
                return cls(*point_tuple)
            elif len(point_tuple) == 7:
                # 7元素版本：缺少enabled字段
                x, y, text, click_type, delay_after, is_image, description = point_tuple
                return cls(x, y, text, click_type, delay_after, is_image, description, True)
            elif len(point_tuple) == 6:
                # 6元素版本：标准版本
                x, y, text, click_type, delay_after, is_image = point_tuple
                return cls(x, y, text, click_type, delay_after, is_image, "", True)
            elif len(point_tuple) == 5:
                # 5元素版本：旧版本，缺少is_image
                x, y, text, click_type, delay_after = point_tuple
                return cls(x, y, text, click_type, delay_after, False, "", True)
            else:
                logger.warning(f"不支持的元组格式，长度: {len(point_tuple)}")
                # 尝试使用默认值
                if len(point_tuple) >= 2:
                    return cls(point_tuple[0], point_tuple[1])
                else:
                    raise ValueError("元组格式不正确")
        except Exception as e:
            logger.error(f"从元组创建Point失败: {e}")
            raise

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'Point':
        """从字典创建Point对象"""
        try:
            return cls(
                x=data.get('x', 0),
                y=data.get('y', 0),
                text=data.get('text', ''),
                click_type=data.get('click_type', '单击'),
                delay_after=data.get('delay_after', 0.5),
                is_image=data.get('is_image', False),
                description=data.get('description', ''),
                enabled=data.get('enabled', True)
            )
        except Exception as e:
            logger.error(f"从字典创建Point失败: {e}")
            raise

    def validate(self) -> Tuple[bool, str]:
        """验证点数据的有效性"""
        try:
            # 验证坐标
            if not isinstance(self.x, int) or not isinstance(self.y, int):
                return False, "坐标必须是整数"

            if self.x < 0 or self.y < 0:
                return False, "坐标不能为负数"

            # 验证点击类型
            valid_click_types = ["单击", "双击", "右键点击"]
            if self.click_type not in valid_click_types:
                return False, f"无效的点击类型: {self.click_type}"

            # 验证延迟
            if not isinstance(self.delay_after, (int, float)) or self.delay_after < 0:
                return False, "延迟必须是非负数"

            if self.delay_after > 60:  # 限制最大延迟为60秒
                return False, "延迟不能超过60秒"

            # 验证文本长度
            if len(self.text) > 1000:
                return False, "文本内容过长"

            # 验证描述长度
            if len(self.description) > 200:
                return False, "描述内容过长"

            return True, "验证通过"

        except Exception as e:
            return False, f"验证过程中出错: {e}"


class PointManager:
    """点管理器 - 完整修复版本"""

    def __init__(self):
        self.points: List[Point] = []
        self._current_index = -1
        self._screen_size = None
        self._get_screen_size()

    def _get_screen_size(self) -> Tuple[int, int]:
        """获取屏幕尺寸 - 修复版本"""
        try:
            if self._screen_size is None:
                self._screen_size = pyautogui.size()
            return self._screen_size
        except Exception as e:
            logger.warning(f"获取屏幕尺寸失败，使用默认值: {e}")
            self._screen_size = (1920, 1080)  # 默认值
            return self._screen_size

    def add_point(self, x: int, y: int, text: str = "", click_type: str = "单击",
                 delay_after: float = 0.5, is_image: bool = False,
                 description: str = "", enabled: bool = True) -> Tuple[bool, str]:
        """添加新点 - 修复版本"""
        try:
            # 创建点对象
            point = Point(x, y, text, click_type, delay_after, is_image, description, enabled)

            # 验证点数据
            is_valid, message = point.validate()
            if not is_valid:
                return False, message

            # 验证坐标有效性
            if not self.validate_coordinates(x, y):
                screen_width, screen_height = self._get_screen_size()
                return False, f"坐标 ({x}, {y}) 超出屏幕范围 ({screen_width}x{screen_height})"

            self.points.append(point)
            logger.info(f"添加点: ({x}, {y}), 类型: {click_type}, 内容: {text[:20] if text else '无'}")
            return True, "点添加成功"

        except Exception as e:
            logger.error(f"添加点失败: {e}")
            return False, f"添加点失败: {e}"

    def delete_point(self, index: int) -> Tuple[bool, str]:
        """删除指定索引的点 - 修复版本"""
        try:
            if 0 <= index < len(self.points):
                removed_point = self.points.pop(index)
                logger.info(f"删除点: ({removed_point.x}, {removed_point.y})")
                return True, f"已删除点 ({removed_point.x}, {removed_point.y})"
            else:
                return False, f"索引 {index} 超出范围"

        except Exception as e:
            logger.error(f"删除点失败: {e}")
            return False, f"删除点失败: {e}"

    def update_point(self, index: int, **kwargs) -> Tuple[bool, str]:
        """更新点的属性 - 修复版本"""
        try:
            if 0 <= index < len(self.points):
                point = self.points[index]

                # 创建更新后的点副本
                updated_data = point.to_dict()
                updated_data.update(kwargs)

                # 创建新点并验证
                new_point = Point.from_dict(updated_data)
                is_valid, message = new_point.validate()
                if not is_valid:
                    return False, message

                # 验证坐标（如果坐标被更新）
                if 'x' in kwargs or 'y' in kwargs:
                    x = kwargs.get('x', point.x)
                    y = kwargs.get('y', point.y)
                    if not self.validate_coordinates(x, y):
                        screen_width, screen_height = self._get_screen_size()
                        return False, f"坐标 ({x}, {y}) 超出屏幕范围 ({screen_width}x{screen_height})"

                # 应用更新
                for key, value in kwargs.items():
                    if hasattr(point, key):
                        setattr(point, key, value)

                logger.info(f"更新点 {index}: {kwargs}")
                return True, "点更新成功"
            else:
                return False, f"索引 {index} 超出范围"

        except Exception as e:
            logger.error(f"更新点失败: {e}")
            return False, f"更新点失败: {e}"

    def update_point_config(self, index: int, click_type: str, delay_after: float) -> Tuple[bool, str]:
        """更新点的配置（点击类型和延迟）"""
        return self.update_point(index, click_type=click_type, delay_after=delay_after)

    def get_point(self, index: int) -> Optional[Point]:
        """获取指定索引的点"""
        if 0 <= index < len(self.points):
            return self.points[index]
        return None

    def get_all_points(self) -> List[Tuple]:
        """获取所有点（元组格式，向后兼容）"""
        return [point.to_tuple() for point in self.points]

    def get_points_as_objects(self) -> List[Point]:
        """获取所有点对象"""
        return self.points.copy()

    def get_enabled_points(self) -> List[Point]:
        """获取所有启用的点"""
        return [point for point in self.points if point.enabled]

    def clear_all_points(self) -> Tuple[bool, str]:
        """清除所有点 - 修复版本"""
        try:
            count = len(self.points)
            self.points.clear()
            logger.info(f"清除所有点，共 {count} 个")
            return True, f"已清除所有 {count} 个点"
        except Exception as e:
            logger.error(f"清除所有点失败: {e}")
            return False, f"清除所有点失败: {e}"

    def move_point_up(self, index: int) -> Tuple[bool, str]:
        """将点上移"""
        try:
            if 0 < index < len(self.points):
                self.points[index], self.points[index-1] = self.points[index-1], self.points[index]
                logger.info(f"点 {index} 上移")
                return True, "点上移成功"
            else:
                return False, "无法上移"
        except Exception as e:
            logger.error(f"点上移失败: {e}")
            return False, f"点上移失败: {e}"

    def move_point_down(self, index: int) -> Tuple[bool, str]:
        """将点下移"""
        try:
            if 0 <= index < len(self.points) - 1:
                self.points[index], self.points[index+1] = self.points[index+1], self.points[index]
                logger.info(f"点 {index} 下移")
                return True, "点下移成功"
            else:
                return False, "无法下移"
        except Exception as e:
            logger.error(f"点下移失败: {e}")
            return False, f"点下移失败: {e}"

    def enable_point(self, index: int) -> Tuple[bool, str]:
        """启用点"""
        return self.update_point(index, enabled=True)

    def disable_point(self, index: int) -> Tuple[bool, str]:
        """禁用点"""
        return self.update_point(index, enabled=False)

    def toggle_point(self, index: int) -> Tuple[bool, str]:
        """切换点的启用状态"""
        try:
            if 0 <= index < len(self.points):
                point = self.points[index]
                new_state = not point.enabled
                return self.update_point(index, enabled=new_state)
            else:
                return False, f"索引 {index} 超出范围"
        except Exception as e:
            logger.error(f"切换点状态失败: {e}")
            return False, f"切换点状态失败: {e}"

    def get_point_count(self) -> int:
        """获取点的数量"""
        return len(self.points)

    def get_enabled_point_count(self) -> int:
        """获取启用的点的数量"""
        return len(self.get_enabled_points())

    def validate_coordinates(self, x: int, y: int) -> bool:
        """验证坐标是否有效 - 修复版本"""
        try:
            screen_width, screen_height = self._get_screen_size()
            return 0 <= x < screen_width and 0 <= y < screen_height
        except Exception as e:
            logger.error(f"验证坐标失败: {e}")
            # 保守验证
            return 0 <= x < 10000 and 0 <= y < 10000

    def export_points(self, file_path: str) -> Tuple[bool, str]:
        """导出点到文件 - 修复版本"""
        try:
            # 验证文件路径
            if not file_path or not isinstance(file_path, str):
                return False, "文件路径无效"

            # 确保目录存在
            directory = os.path.dirname(file_path)
            if directory and not os.path.exists(directory):
                os.makedirs(directory, exist_ok=True)

            # 准备导出数据
            export_data = {
                "version": "2.0",
                "export_time": self._get_timestamp(),
                "point_count": len(self.points),
                "points": [point.to_dict() for point in self.points]
            }

            # 写入文件
            with open(file_path, 'w', encoding='utf-8') as f:
                json.dump(export_data, f, ensure_ascii=False, indent=2)

            logger.info(f"导出 {len(self.points)} 个点到 {file_path}")
            return True, f"成功导出 {len(self.points)} 个点到 {file_path}"

        except Exception as e:
            logger.error(f"导出点失败: {e}")
            return False, f"导出点失败: {e}"

    def import_points(self, file_path: str, merge: bool = False) -> Tuple[bool, str]:
        """从文件导入点 - 修复版本"""
        try:
            if not os.path.exists(file_path):
                return False, f"文件不存在: {file_path}"

            # 读取文件
            with open(file_path, 'r', encoding='utf-8') as f:
                import_data = json.load(f)

            # 验证数据格式
            if not isinstance(import_data, dict) or "points" not in import_data:
                return False, "文件格式不正确"

            points_data = import_data["points"]
            if not isinstance(points_data, list):
                return False, "点数据格式不正确"

            # 解析点数据
            imported_points = []
            for i, point_data in enumerate(points_data):
                try:
                    if isinstance(point_data, dict):
                        point = Point.from_dict(point_data)
                    elif isinstance(point_data, (list, tuple)):
                        point = Point.from_tuple(point_data)
                    else:
                        logger.warning(f"跳过无法解析的点数据: {point_data}")
                        continue

                    # 验证点
                    is_valid, message = point.validate()
                    if not is_valid:
                        logger.warning(f"跳过无效点 {i}: {message}")
                        continue

                    imported_points.append(point)

                except Exception as e:
                    logger.warning(f"解析点 {i} 失败: {e}")
                    continue

            # 应用导入的点
            if not merge:
                self.points.clear()

            self.points.extend(imported_points)

            logger.info(f"从 {file_path} 导入 {len(imported_points)} 个点")
            return True, f"成功导入 {len(imported_points)} 个点"

        except Exception as e:
            logger.error(f"导入点失败: {e}")
            return False, f"导入点失败: {e}"

    def find_points_near(self, x: int, y: int, radius: int = 10) -> List[Tuple[int, Point]]:
        """查找指定坐标附近的点"""
        nearby_points = []
        for i, point in enumerate(self.points):
            distance = ((point.x - x) ** 2 + (point.y - y) ** 2) ** 0.5
            if distance <= radius:
                nearby_points.append((i, point, distance))

        # 按距离排序
        nearby_points.sort(key=lambda item: item[2])
        return [(i, point) for i, point, _ in nearby_points]

    def get_point_statistics(self) -> Dict[str, Any]:
        """获取点统计信息"""
        total_points = len(self.points)
        enabled_points = self.get_enabled_point_count()

        click_type_count = {}
        image_count = 0
        text_count = 0

        for point in self.points:
            click_type_count[point.click_type] = click_type_count.get(point.click_type, 0) + 1
            if point.is_image:
                image_count += 1
            if point.text:
                text_count += 1

        return {
            "total_points": total_points,
            "enabled_points": enabled_points,
            "disabled_points": total_points - enabled_points,
            "click_type_distribution": click_type_count,
            "image_points": image_count,
            "text_points": text_count,
            "empty_points": total_points - image_count - text_count
        }

    def duplicate_point(self, index: int) -> Tuple[bool, str]:
        """复制点"""
        try:
            if 0 <= index < len(self.points):
                original_point = self.points[index]
                # 创建副本并稍微偏移坐标
                new_point = Point(
                    x=original_point.x + 10,
                    y=original_point.y + 10,
                    text=original_point.text,
                    click_type=original_point.click_type,
                    delay_after=original_point.delay_after,
                    is_image=original_point.is_image,
                    description=f"{original_point.description} (副本)",
                    enabled=original_point.enabled
                )

                self.points.insert(index + 1, new_point)
                logger.info(f"复制点 {index}")
                return True, "点复制成功"
            else:
                return False, f"索引 {index} 超出范围"
        except Exception as e:
            logger.error(f"复制点失败: {e}")
            return False, f"复制点失败: {e}"

    def _get_timestamp(self) -> str:
        """获取时间戳"""
        from datetime import datetime
        return datetime.now().strftime("%Y-%m-%d %H:%M:%S")

    def validate_all_points(self) -> Tuple[bool, List[Tuple[int, str]]]:
        """验证所有点"""
        errors = []
        for i, point in enumerate(self.points):
            is_valid, message = point.validate()
            if not is_valid:
                errors.append((i, message))

        # 验证坐标
        for i, point in enumerate(self.points):
            if not self.validate_coordinates(point.x, point.y):
                errors.append((i, f"坐标 ({point.x}, {point.y}) 超出屏幕范围"))

        return len(errors) == 0, errors